package com.zyb.ext.linkedlist;

public class MyLinkedList<E> implements MyList<E> {
    private int size = 0;
    private Node<E> first;
    private Node<E> last;

    public MyLinkedList() {
    }

    @Override
    public boolean add(E e) {
        Node<E> newNode = new Node<>();
        newNode.element = e;
        //第一个元素为空，表示此集合为空
        if (first == null) {
            //第一次插入，设置首节点
            first = newNode;
        } else {
            //将新节点设置为旧链表的最后节点的下一个节点
            last.nextNode = newNode;
            //将旧链表的最后一个节点设置为新节点的上一个节点
            newNode.preNode = last;
        }
        //将新插入的节点作为链表的末节点
        last = newNode;
        size++;
        return true;
    }

    @Override
    public boolean add(int index, E e) {
        checkForAddOrRemove(index);
        Node<E> newNode = new Node<>();
        newNode.element = e;
        //判断是否是最后一个节点添加
        if (index == (size - 1)) {
            add(e);
        } else {
            if (first == null) {
                first = newNode;
                last = newNode;
            } else {
                //获取此索引处的节点
                Node<E> indexNode = getNodeByIndex(index);
                //获取此索引处的上一个节点
                Node<E> preNode = indexNode.preNode;
                //把新节点的下一个节点设置为indexNode
                newNode.nextNode = indexNode;
                //把新节点的上一个节点设置为preNode
                newNode.preNode = preNode;
                //把上节点的下节点设置为新节点
                preNode.nextNode = newNode;
                //当前节点的上一个节点是新节点
                indexNode.preNode = newNode;
            }
            size++;
        }
        return true;
    }

    private void checkForAddOrRemove(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("索引越界异常...");
        }
    }

    @Override
    public E get(int index) {
        Node<E> nextNode = getNodeByIndex(index);
        return nextNode.element;
    }

    private Node<E> getNodeByIndex(int index) {
        checkElementIndex(index);
        Node<E> nextNode = first;
        //判断是否为最后一个节点
        if (index == (size - 1)) {
            nextNode = last;
        } else {
            //判断是否是从第二个节点开始查找
            for (int i = 0; i < index; i++) {
                nextNode = nextNode.nextNode;
            }
        }
        return nextNode;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public E remove(int index) {
        checkElementIndex(index);
        Node<E> nowFirst = null;
        //如果移除的为首节点
        if (index == 0) {
            //获取第二个节点
            Node<E> nextNode = first.nextNode;
            nowFirst = this.first;
            //第二个节点的上一个节点置空
            nextNode.preNode = null;
            //把第二个节点作为首节点
            first = nextNode;
        } else if (index == (size - 1)) {
            //判断移除的是否为末节点
            nowFirst = last;
            //获取末节点的上一个节点
            Node<E> preNode = last.preNode;
            //末节点的下一个节点置空
            preNode.nextNode = null;
            //把倒数第二个节点作为末节点
            last = preNode;
        } else {
            //获取当前索引的节点
            nowFirst = getNodeByIndex(index);
            //获取当前索引的节点的上一个节点
            Node<E> preNode = nowFirst.preNode;
            //获取当前索引的节点下一个节点
            Node<E> nextNode = nowFirst.nextNode;
            //设置下一个节点
            preNode.nextNode = nextNode;
            //设置上一个节点
            nextNode.preNode = preNode;
        }
        size--;
        return nowFirst.element;
    }

    @Override
    public boolean remove(E e) {
        if (e == null) {
            throw new RuntimeException("remove 入参元素值为空！");
        }
        //获取当前元素的索引
        int index = getByElement(e);
        if (index > -1) {
            //如果存在，则移除
            remove(index);
            return true;
        }
        return false;
    }

    @Override
    public int getByElement(E e) {
        if (size == 0) {
            throw new RuntimeException("此集合为空！");
        }
        Node<E> nowNode = this.first;
        for (int i = 0; i < size; i++) {
            //遍历，如果元素相等，则返回索引
            if (nowNode.element.equals(e)) {
                return i;
            }
            nowNode = nowNode.nextNode;
        }
        return -1;
    }

    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException("索引越界异常...");
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private class Node<E> {
        E element;
        Node<E> preNode;
        Node<E> nextNode;
    }
}
